Using VHDL Code Generator
Icarus Verilog contains a code generator to emit VHDL from the Verilog netlist. This allows Icarus Verilog to function as a Verilog to VHDL translator. Invocation To translate a Verilog program to VHDL, invoke "iverilog" with the -tvhdl flag. % iverilog -t vhdl -o my_design.vhd my_design.v The generated VHDL will be placed in a single file (a.out by default), even if the Verilog is spread over multiple files. Flags Flag Description -pdebug=1 Print progress messages as the code generator visits each part of the design. -pdepth=N Only output VHDL entities for modules found at depth < N in the hierarchy. N=0, the default, outputs all entities. For example, -pdepth=1 outputs only the top-level entity. Supported Constructs // Benchmark "top" written by ABC on Thu Jul 24 17:34:52 2014 ☀`timescale 1ns / 1ps ////////////////////////////////////////////////////////////////////////////////// // Company: // Engineer: // // Create Date: 02:26:40 09/09/2014 // Design Name: // Module Name: mux2_1bus // Project Name: // Target Devices: // Tool versions: // Description: // // Dependencies: // // Revision: // Revision 0.01 - File Created // Additional Comments: // ////////////////////////////////////////////////////////////////////////////////// module mux4_4bus( input 3:0 I0, input 3:0 I1, input 3:0 I2, input 3:0 I3, input 3:0 I4, input 3:0 I5, input 3:0 I6, input 3:0 I7, input 2:0 Sel, output 3:0 Y ); assign Y = ( Sel 0 )? I0 : ( Sel 1 )? I1 : ( Sel 2 )? I2 : ( Sel 3 )? I3 : ( Sel 4 )? I4 :( Sel 5 )? I5 :( Sel 6 )? I6 : I7; endmodule A Verilog module produces a VHDL entity/architecture pair with the same input and output ports. Any modules instantiated within the module produce both a VHDL component instantiation statement and a component declaration. The code generator can identify most cases when a Verilog "out" port needs to be a "buffer" port in VHDL (i.e. when the signal needs to be read inside the entity). reg 8:0 PaddlePosition; reg 2:0 quadAr, quadBr; always @(posedge clk) quadAr <= {quadAr1:0, quadA}; always @(posedge clk) quadBr <= {quadBr1:0, quadB}; always @(posedge clk) if(quadAr2 ^ quadAr1 ^ quadBr2 ^ quadBr1) begin if(quadAr2 ^ quadBr1) begin if(~&PaddlePosition) // make sure the value doesn't overflow PaddlePosition <= PaddlePosition + 1; end else begin if(|PaddlePosition) // make sure the value doesn't underflow PaddlePosition <= PaddlePosition - 1; end end Processes Both initial and always processes are converted to VHDL processes. The only difference is that an initial process has a indefinite wait statement at the end, so it is only activated once, at time step zero. For example, an empty initial process like this: initial begin end Produces a VHDL process like this: process is begin wait; end process; Sensitivity lists for always processes are handled differently depending on whether the events are edge- or level-sensitive. An edge-sensitive event, or a mix of edge- and level-sensitive events, produces a wait-until statement at the start of the process: always @(posedge x) ... process is begin wait until rising_edge(x); ... A level-sensitive event produces a wait-on statement at the end of the process: always @(x) ... process is begin ... wait on x; end process; This means that the body of a level-sensitive process with execute once at time step zero. Note that neither event type produces a VHDL sensitivity list: this is because VHDL does not allow any wait statements in a process with a sensitivity list, and hence Verilog processes with delays could not be translated correctly. These two styles of processes are consistent with the coding guidelines of Xilinx and other VHDL vendors. If all assignments in an edge-sensitive always process are non-blocking (<= instead of =''', ''unconfirmed''), the generated VHDL process doesn't use wait statements: always @(posedge clk or negedge rstn) begin if (!rstn) ... else ... end process (rx_clk, rx_rstn) is begin if ((not rstn) = '1') then ... elsif rising_edge(clk) then ... end if; end process; Functions Verilog functions are translated directly to VHDL functions. A special variable _Result holds the return value of the function. For example: '''assign DAC_data = cnt10 ? ~cnt9:0 : cnt9:0; function sum ( a : unsigned(15 downto 0); b : unsigned(15 downto 0) ) return unsigned is variable sum_Result : unsigned(15 downto 0); begin sum_Result := (a + b); return sum_Result; end function; Unlike Verilog functions, VHDL functions may not read global variables, and this restriction also applies to functions generated from Verilog. The Verilog-2001 "automatic" keyword is supported and generates recursive VHDL functions. Tasks Signals and Types Single-bit signals are converted to VHDL std_logic signals. Multi-bit vectors are converted to the signed/unsigned types from the ieee.numeric_std package. Conversion between these types is handled automatically, as is conversion from Boolean to std_logic values. The mapping between Verilog signal values and std_logic values is as follows: Verilog value VHDL value 0 0 1 1 Z Z X U ? - Drive strengths are not yet implemented. Signal names which conflict with VHDL reserved words, differ only in case to another signal name, or are otherwise invalid as VHDL signal names are automatically renamed -- usually by prefixing "VL_". Logic Gates Primitive logic gates are translated to VHDL concurrent assignment statements. For example: and(Z, X, Y); Z <= X and Y; Assignment Verilog blocking and non-blocking assignment are implemented using the the VHDL signal assignment operator. Non-blocking assignment in Verilog has the same semantics as signal assignment in VHDL. For example, the following statement schedules the update of X at the next delay statement in Verilog, or wait statement in VHDL, or the end of the process: X <= Y; However, the Verilog blocking assignment operator schedules the update immediately. To emulate this in Verilog a zero-time wait is added after the assignment; this causes the VHDL simulator to schedule the update immediately after the statement has executed. For example, this Verilog statement: X = Y; Produces the following VHDL statements: X <= Y; wait for 0 ns; The zero-delay wait is omitted if the statement is the last in the process, or the immediately following statement was a wait anyway. Branching and Looping Verilog if statements are translated directly to VHDL if statements which have identical semantics. Verilog case statements can be translated to VHDL case statements provided the control and test expressions are "locally static" (basically, signal references or constants). If the control expression is not locally static, the VHDL code generator will assign it to a temporary variable immediately before the case statement and use that temporary as the control expression. For example, the following control expression would produce an invalid VHDL case statement: case (cond&4'b1110) ... So the code generator produces code to evaluate the expression separately and store it in a temporary: variable Verilog_Case_Ex : unsigned(3 downto 0); begin Verilog_Case_Ex := (cond and "1110"); case Verilog_Case_Ex is ... Test expression that are not locally static will currently produce invalid VHDL. Time and Delays User-defined Primitives Limitations Signal Values and Resolution There are several cases where the behaviour of the translated VHDL deviates from the source Verilog: * The result of division by zero is x in Verilog but raises an exception in VHDL. * Similarly, the result of reading past the end of an array in Verilog is x, whereas VHDL raises an exception. * Any signal that is driven by two or more processes will have the value 'U'. This is the result of the signal resolution function in the std_logic_1164 package. Constructs not Supported The following Verilog constructs cannot be translated to VHDL: * fork and join * force and release * disable * real-valued variables * switches * hierarchical dereferencing Other Limitations * The test expressions in case statements must be constant. * Translation of a parameter to a corresponding VHDL generic declaration. Instead the default parameter value is used.